package com.tange.module.login.line;

import static com.appbase.custom.constant.CommonConstants.LOGIN_CHANNEL_LINE;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.KeyEvent;

import androidx.core.util.Consumer;

import com.appbase.custom.constant.CommonConstants;
import com.demo.view.LoadingDialog;
import com.linecorp.linesdk.LineAccessToken;
import com.linecorp.linesdk.LineApiResponse;
import com.linecorp.linesdk.LineProfile;
import com.linecorp.linesdk.Scope;
import com.linecorp.linesdk.api.LineApiClient;
import com.linecorp.linesdk.api.LineApiClientBuilder;
import com.linecorp.linesdk.auth.LineAuthenticationParams;
import com.linecorp.linesdk.auth.LineLoginApi;
import com.linecorp.linesdk.auth.LineLoginResult;
import com.tange.core.builtin.account.LoginRet;
import com.tange.core.builtin.account.third.ThirdAccount;
import com.tange.core.data.structure.Resp;
import com.tg.appcommon.android.LanguageUtils;
import com.tange.base.toolkit.PreferenceUtil;
import com.tange.base.toolkit.StatusBarUtil;
import com.tg.appcommon.android.TGLog;
import com.tange.base.toolkit.TGThreadPool;
import com.tg.appcommon.android.TGToast;
import com.tg.appcommon.router.TGBusiness;
import com.tg.data.http.entity.LoginBean;
import com.tg.loginex.helper.LoginHelper;

import java.util.Arrays;
import java.util.List;

public class LineLoginActivity extends Activity {

    private static final String TAG = "LineLoginActivityTAG";

    private static final int MAX_RETRY_COUNT = 1;

    private static final int LINE_REQUEST_CODE = 5566;

    private static final long TIME_DAY = 24 * 60 * 60 * 1000;

    private LoadingDialog mLoadingDialog;

    private int retryCount = 0;

    protected void showLoading() {
        if (mLoadingDialog == null) {
            mLoadingDialog = new LoadingDialog(this);
            mLoadingDialog.setMsg(com.module.commonui.R.string.loging);
            mLoadingDialog.setCancelable(false);
        }
        if (!isFinishing() && !isDestroyed()) {
            mLoadingDialog.show();
        }
    }

    protected void hideLoading() {
        if (mLoadingDialog != null && mLoadingDialog.isShowing()) {
            mLoadingDialog.cancel();
        }
    }

    public boolean checkLineInstalled() {

        PackageManager pm = getPackageManager();
        if (pm == null) {
            return false;
        }

        try {
            List<PackageInfo> packageInfoList = pm.getInstalledPackages(0);
            if (packageInfoList != null) {
                for (PackageInfo pi : packageInfoList) {
                    if (TextUtils.equals("jp.naver.line.android", pi.packageName)) {
                        return true;
                    }
                }
            }
        } catch (Throwable ex) {
            TGLog.i(TAG, "checkLineInstalled: e = " + ex);
        }

        return false;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        StatusBarUtil.setStatusBarTransparent(this);
        setContentView(R.layout.tange_activity_line_login);

        showLoading();

        TGLog.i(TAG, "onCreate: ");

        try {
            LineApiClientBuilder apiClientBuilder = new LineApiClientBuilder(getApplicationContext(), getString(R.string.line_channel_id));
            LineApiClient lineApiClient = apiClientBuilder.build();

            final LineAccessToken accessToken = lineApiClient.getCurrentAccessToken().getResponseData();

            if (accessToken != null) {
                TGLog.i(TAG, "onCreate: login success before , expires after " + (accessToken.getExpiresInMillis() / TIME_DAY) + " day");

                TGLog.i(TAG, "onCreate: login success before , accessToken =  " + accessToken.getTokenString());
            }

            if (accessToken != null && accessToken.getExpiresInMillis() > TIME_DAY) {

                TGLog.i(TAG, "onCreate: try to get profile ...");

                TGThreadPool.execute(() -> {

                    LineProfile profile = null;
                    try {
                        LineApiResponse<LineProfile> lineProfileLineApiResponse = lineApiClient.getProfile();
                        TGLog.i(TAG, "onCreate: lineProfileLineApiResponse = " + lineProfileLineApiResponse);
                        if (lineProfileLineApiResponse != null && lineProfileLineApiResponse.isSuccess()) {
                            profile = lineProfileLineApiResponse.getResponseData();
                        }
                    } catch (Throwable e2) {
                        TGLog.i(TAG, "onCreate: ERROR try to get profile = " + e2);
                    }

                    final LineProfile finalProfile = profile;

                    TGLog.i(TAG, "onCreate: final profile = " + finalProfile);

                    String lastIdToken = PreferenceUtil.getString(LineLoginActivity.this, CommonConstants.LINE_ID_TOKEN, "");
                    if (!TextUtils.isEmpty(lastIdToken)) {
                        TGLog.i(TAG, "onCreate: login success before , idToken = " + lastIdToken);
                        TGThreadPool.executeOnUiThreadDelayed(() -> notifySuccess(lastIdToken, finalProfile), 0);
                    } else {
                        TGLog.i(TAG, "onCreate: empty idToken , start a new login !");
                        TGThreadPool.executeOnUiThreadDelayed(() -> startNewLineLogin(), 0);
                    }
                });

                return;
            }

        } catch (Throwable ex) {
            TGLog.i(TAG, "onCreate: failed to get pre token : " + ex.getMessage());
        }

        startNewLineLogin();
    }

    private void startNewLineLogin() {

        // 清除之前保存的idToken
        PreferenceUtil.setString(LineLoginActivity.this, CommonConstants.LINE_ID_TOKEN, "");

        if (!checkLineInstalled()) {
            TGLog.i(TAG, "onCreate: line apk not installed");
            Intent intent = new Intent();
            intent.putExtra("msg", getResources().getString(R.string.login_been_canceled));
            setResult(RESULT_CANCELED, intent);
            finish();
            TGToast.showToast(R.string.line_app_not_installed);
            return;
        }

        try {
            Intent loginIntent = LineLoginApi.getLoginIntent(
                    this,
                    getString(R.string.line_channel_id),
                    new LineAuthenticationParams.Builder()
                            .scopes(Arrays.asList(Scope.OPENID_CONNECT, Scope.OC_EMAIL, Scope.PROFILE))
                            .build());
            startActivityForResult(loginIntent, LINE_REQUEST_CODE);

            TGLog.i(TAG, "startNewFacebookLogin: start a new login ... ");
        } catch (Throwable ex) {
            TGLog.i(TAG, "startNewFacebookLogin: ERROR start a new login  = " + ex.getMessage());
            notifyCancel("[LINE] " + ex.getMessage());
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            TGLog.i(TAG, "ignore KEYCODE_BACK");
            return true;
        } else {
            return super.onKeyDown(keyCode, event);
        }
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        TGLog.i(TAG, "[onActivityResult]");

        if (requestCode != LINE_REQUEST_CODE) {
            TGLog.e(TAG, "[onActivityResult] not same request code");
            return;
        }

        LineLoginResult result = LineLoginApi.getLoginResultFromIntent(data);

        TGLog.e(TAG, "[onActivityResult] result = " + result);

        if (result == null) {
            notifyCancel("[LINE] Failed: empty activity result");
            return;
        }

        TGLog.e(TAG, "[onActivityResult] result.getResponseCode() = " + result.getResponseCode());

        switch (result.getResponseCode()) {

            case SUCCESS:
                if (result.getLineIdToken() == null || result.getLineCredential() == null) {
                    notifyCancel("[LINE] Failed: empty id token");
                } else {
                    TGLog.i(TAG, "[LINE] get id token success = " + result.getLineIdToken());
                    TGLog.i(TAG, "[LINE] get access token success = " + result.getLineCredential().getAccessToken().getTokenString());
                    notifySuccess(result.getLineIdToken().getRawString(), result.getLineProfile());
                }
                break;

            case AUTHENTICATION_AGENT_ERROR:
            case CANCEL:
                notifyCancel(getResources().getString(R.string.login_been_canceled));
                break;

            default:
                TGLog.e(TAG, "[onActivityResult] Login FAILED!");
                TGLog.e(TAG, "[onActivityResult] " + result.getErrorData());
                notifyCancel("[LINE] Failed: " + result.getErrorData());
                break;
        }
    }

    private void notifyCancel(String s) {
        Intent intent = new Intent();
        intent.putExtra("msg", s);
        setResult(RESULT_CANCELED, intent);
        finish();
        TGToast.showToast(s);
    }

    private void notifySuccess(String idToken, LineProfile lineProfile) {
        TGLog.i(TAG, "[notifySuccess] idToken = " + idToken);
        TGLog.i(TAG, "[notifySuccess] lineProfile = " + lineProfile);
        final String userName = lineProfile != null ? lineProfile.getDisplayName() : "LINE User";
        ThirdAccount.INSTANCE.line(idToken, LanguageUtils.getCountry(this), new Consumer<Resp<LoginRet>>() {
                    @Override
                    public void accept(Resp<LoginRet> loginRetResp) {
                        if (loginRetResp.getSuccess()){
                            LoginRet loginRet = loginRetResp.getData();
                            LoginBean content = new LoginBean();
                            content.setNickname(userName);
                            content.setToken(loginRet.getAccessToken());
                            content.setId(String.valueOf(loginRet.getId()));
                            long expiresInSeconds = loginRet.getExpiresInSeconds() * 1000 + System.currentTimeMillis();
                            content.setCreated_at(expiresInSeconds);
                            final Handler h = new Handler(Looper.getMainLooper());
                            h.post(() -> {
                                String token = content.getToken();
                                TGLog.i(TAG, "loginWithTG: onSuccess token = " + token);
                                Intent retIntent = new Intent();
                                retIntent.putExtra("token", token);
                                retIntent.putExtra("name", userName);
                                retIntent.putExtra("id", content.getId());
                                setResult(RESULT_OK);
                                finish();

                                // 保存idToken下次直接用
                                PreferenceUtil.setString(LineLoginActivity.this, CommonConstants.LINE_ID_TOKEN, idToken);

                                PreferenceUtil.setBoolean(LineLoginActivity.this, CommonConstants.PRE_PROTOCOL_AGREE, true);
                                LoginHelper.saveUserInfo(content, userName, "");
                                LoginHelper.saveLastLoginChannel(LOGIN_CHANNEL_LINE);
                                TGBusiness.getAppModule().goToDeviceListPage(LineLoginActivity.this);
                            });
                        }else{
                            TGLog.i(TAG, "loginWithTG: onResponseError: errorCode = " + loginRetResp.getCode() + " , errorInfo = " + loginRetResp.getMessage());
                            if (retryCount < MAX_RETRY_COUNT) {
                                retryCount++;
                                TGLog.i(TAG, "loginWithTG: onResponseError: retry ... ");

                                // 只要后台返回错误，就注销之前的信息，重新发起登录
                                LineLoginProxy.logout(LineLoginActivity.this, () -> {
                                    TGLog.i(TAG, "loginWithTG: onResponseError: start new login ");
                                    startNewLineLogin();
                                });
                            } else {
                                TGToast.showToast("[TG-ERROR] " + loginRetResp.getCode() + " , " + loginRetResp.getMessage());
                                finish();
                            }
                        }

                    }
                });
    }

    @Override
    protected void onDestroy() {
        TGLog.i(TAG, "[onDestroy]");
        super.onDestroy();
        hideLoading();
    }
}
